<script setup lang="ts">
import {PropType, reactive, ref} from 'vue'
import {ElMessage, FormRules} from 'element-plus'
import {IconConfig} from '@/api/config'
import {SeleteData} from '@/api/config'
import {fileHeadCheck, fileSizeCheck, getIdCardInfor, NoNumber, Number, PhoneNumber} from '@/util/common'
import {readXLSX} from '@/util/excel'
import {importResidenArchives, ResidentList} from '@/api/publicHealthExamination/residentArchives'
import dIcon from '@/components/dIcon.vue'
import dDialog from '@/components/dDialog/dDialog.vue'
import dFrom from '@/components/dFrom/dFrom.vue'
import {FromItem} from '@/components/dFrom/dFrom'

const emits = defineEmits(['close'])

const props = defineProps({
  //显示
  showDialog: {
    type: Boolean,
    required: true
  },
  // 社区下拉
  selectTeamLsit: {
    type: Array as PropType<Array<SeleteData>>,
    required: true,
    defult: () => []
  },
  // 民族字典
  seleteNationData: {
    type: Array as PropType<Array<SeleteData>>,
    required: true,
    defult: () => []
  }
})

//表单项
const fromItems = ref<Array<FromItem>>([
  {
    label: '社区',
    placeholder: '请选择社区',
    prop: 'teamId',
    type: 'selete',
    filterable: true,
    seleteData: props.selectTeamLsit
  }
])

// 表单规则
const rules = reactive<FormRules>({
  teamId: [{required: true, message: '请选择社区', trigger: ['change', 'blur']}]
})

//信息
const formData: {teamId: string} = reactive({teamId: ''})

//表单清除控制
const resetFieldsFlag = ref(false)
// 表单校验
const validateFlag = ref(false)
// 暂存文件内容
const fileContent = ref()

//文件名称
const fileName = ref('')
//文件数据
const fileData = ref<Array<ResidentList>>([])
// 错误信息
const errorRowMsg = ref('')

//上传中加载状态
const showUpBtnLoading = ref(false)
// 文件上传Dom
const seleteInput = ref<HTMLInputElement>()

//重置数据
const resetData = () => {
  fileName.value = ''
  errorRowMsg.value = ''
  fileData.value = []
  showUpBtnLoading.value = false
  fileContent.value = null
}

// 关闭弹窗
const onClose = () => {
  emits('close')
  resetData()
  resetFieldsFlag.value = !resetFieldsFlag.value
}

// 数据校验过滤
const pattern = {
  name: (value: string) => {
    // 姓名校验不通过返回 undefined
    if (!value || !NoNumber.test(value) || value.length > 20) {
      return undefined
    } else {
      return value
    }
  },
  idNo: (value: string) => {
    // 身份证校验不通过返回 undefined
    const infor = getIdCardInfor(value) // 身份证有效性校验
    if (!value || infor.age === null && infor.sex === null) {
      return undefined
    } else {
      return value
    }
  },
  gender: (value: string) => {
    // 性别校验不通过返回 undefined
    if (!value) {
      return undefined
    } else {
      // 性别
      return value
    }
  },
  age: (value: string) => {
    // 年龄校验不通过返回 undefined
    if (!value || !Number.test(value) || value.length > 3) {
      return undefined
    } else {
      return value
    }
  },
  nation: (value: string) => {
    // 民族校验不通过返回 undefined
    if (!value) {
      return undefined
    } else {
      let nation
      // 遍历民族字典，返回字典值
      props.seleteNationData.forEach((item) => {
        item.label === value && (nation = item.value)
      })
      return nation
    }
  },
  phone: (value: string) => {
    // 电话号码校验不通过返回 undefined
    if (!value || !PhoneNumber.test(value) || value.length > 11) {
      return undefined
    } else {
      return value
    }
  },
  address: (value: string) => {
    // 地址校验不通过返回 undefined
    if (!value || value.length > 100) {
      return undefined
    } else {
      return value
    }
  }
}

//检查文件
const checkHeader = (file: File) => {
  return new Promise((resolve, reject) => {
    if (!fileSizeCheck(file.size, 20, 'MB')) {
      ElMessage.warning('文件不应大于20M')
      reject()
    } else {
      // 检查文件
      fileHeadCheck(file, 'xlsx')
        .then(() => {
          return file.arrayBuffer()
        })
        .then((buffer) => {
          // 读取excel文件
          return readXLSX(
            buffer,
            'YYYY-MM-DD HH:mm:ss',
            {
              姓名: 'name',
              身份证号: 'idNo',
              性别: 'gender',
              '年龄（岁）': 'age',
              民族: 'nation',
              联系电话: 'phone',
              详细地址: 'address'
            },
            pattern,
            false,
            false,
            3
          )
        })
        .then((res) => {
          //表格头不完整
          if (res.unSetColProp && Object.keys(res.unSetColProp).length) {
            ElMessage.error('文件表头缺少必要信息,请检查表格数据是否按照模板填写')
            reject()
          }
          // 校验不通过的行提示
          else if (res.hasErrorData) {
            errorRowMsg.value = `表格中第${res.errorRowNumbers.join('、')}行数据格式错误，表格导入失败，请检查表格内容后重新导入`
            reject()
          } else {
            fileData.value = res.allData
            resolve(res)
          }
        })
        .catch(() => {
          ElMessage.warning('请选择xlsx文件')
          reject()
        })
    }
  })
}

//选择文件后
const onSeleteFile = (evt: Event) => {
  const target = evt.currentTarget as HTMLInputElement
  if (target.files && target.files[0]) {
    resetData() // 先重置数据
    const file = target.files[0]
    fileContent.value = file //文件内容
    fileName.value = file.name // 文件名
    target.value = ''
  }
}
//选择文件按钮
const seleteBtnIcon: IconConfig = {
  type: 'custom',
  icon: 'common-import',
  size: 16
}

/**
 * @description: 选择文件按钮触发
 * @return {*}
 */
const onSeleteClick = () => {
  const input = seleteInput.value
  if (input) {
    input.click()
  }
}

const onComfirm = () => {
  validateFlag.value = !validateFlag.value
}

/**
 * @description: 导入名单
 * @return {*}
 */
const onUpload = () => {
  if (!fileContent.value) {
    ElMessage.error('请选择导入文件！')
    return
  }
  showUpBtnLoading.value = true
  // 读取文件数据
  checkHeader(fileContent.value)
    .then(() => {
      const params = {
        teamId: formData.teamId,
        personList: fileData.value
      }
      // 上传数据给后端
      importResidenArchives(params)
        .then(() => {
          ElMessage.success('导入成功！')
          onClose()
        })
        .catch((err) => {
          console.warn(err)
          errorRowMsg.value = '导入失败'
        })
        .finally(() => {
          showUpBtnLoading.value = false
        })
    })
    .catch((err) => {
      showUpBtnLoading.value = false
      console.warn(err)
    })
}
</script>

<template>
  <d-dialog
    title="导入名单"
    :width="700"
    :show-dialog="props.showDialog"
    :btntext="showUpBtnLoading ? '导入中' : '保存'"
    :cancel-text="showUpBtnLoading ? '关闭' : '取消'"
    :hide-save-btn="!!errorRowMsg"
    :show-save-loading="showUpBtnLoading"
    @confirm="onComfirm"
    @cancel="onClose"
    @close="onClose"
  >
    <div v-if="!errorRowMsg">
      <d-from
        label-position="left"
        :label-width="55"
        :reset-fields-flag="resetFieldsFlag"
        :validate-flag="validateFlag"
        :rules="rules"
        :form-data="formData"
        :form-items="fromItems"
        @submit="onUpload"
      />
      <el-button type="primary" @click="onSeleteClick">
        <d-icon class="el-icon el-icon--left" :icon-config="seleteBtnIcon" />
        选择文件
      </el-button>
      <input ref="seleteInput" class="import-selete-input" type="file" accept=".xlsx" @change="onSeleteFile">
      <h1 v-if="!fileName" class="import-linespace import-selete-title d-common-text-main">
        请选择xlsx文件，大小限制为20M
      </h1>
      <div v-if="fileName" class="import-linespace d-common-text-main">
        {{ fileName }}
      </div>
    </div>
    <div v-if="!!errorRowMsg" class="import-linespace d-common-text-main">
      {{ errorRowMsg }}
    </div>
  </d-dialog>
</template>

<style scoped>
.import-selete-input {
  display: none;
}
.import-linespace {
  margin-top: 10px;
}
.import-selete-title {
  color: var(--d-font-color-tab);
}
.import-file-complete {
  margin-left: 8px;
}
.import-file--success {
  color: var(--el-color-primary);
}
</style>
